﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;
using System.Collections;
using MapControl.Misc.DAL;

namespace MapControl.Misc
{
    public class ComPort
    {
        private SerialPort comPort;
        public List<string> ListMessages = new List<string>();
        public List<BaseGPSPoint> gpsPointList;
        private string _baudRate = string.Empty;
        private string _stopBits = string.Empty;
        private string _dataBits = string.Empty;
        private string _parity = string.Empty;
        private string _portName = string.Empty;

        private bool _isText = true;
        private ToolStripLabel lblSendingStatus;
        private int CountReceived=0;
        //variable for sending file
        private string filename;
        private byte[] buffer;
        private int _BytesToRead;
        private int count=0;

        //HT Code:
        //Tên biến trả về
        public readonly string ACK_MSG = "NAME-ACK";

        #region Constructor

        public ComPort()
        {

        }
        public ComPort(string portName, string baudRate, string stopBits, string dataBits, string parity, bool isText)
        {
            //khởi tạo
            _baudRate = baudRate;
            _stopBits = stopBits;
            _dataBits = dataBits;
            _parity = parity;
            _portName = portName;
            //_isText = isText;

            

            comPort = new SerialPort();
            comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
            comPort.ErrorReceived+=new SerialErrorReceivedEventHandler(comPort_ErrorReceived);
        }
        #endregion

        #region Properties
        public string FileName
        {
            set { filename = value; }
            get { return filename; }
        }

        public int Count
        {
            set { count = value; }
            get { return count; }
        }

        public byte[] BufferByteArr
        {
            set { buffer = value; }
            get { return buffer; }
        }

        public int BytesToRead
        {
            set { _BytesToRead = value; }
            get { return _BytesToRead; }
        }

        public string BaudRate
        {
            set { _baudRate = value; }
            get { return _baudRate; }
        }
        public string StopBits
        {
            set { _stopBits = value; }
            get { return _stopBits; }
        }
        public string DataBits
        {
            set { _dataBits = value; }
            get { return _dataBits; }
        }
        public string Parity
        {
            set { _parity = value; }
            get { return _parity; }
        }
        public string PortName
        {
            set { _portName = value; }
            get { return _portName; }
        }

        #endregion

        #region Events
       
        /// <summary>
        /// HT Code: Khởi tạo chuỗi lệnh để gửi qua cổng COM
        /// Cấu trúc khởi tạo: "{[DATA]}\r"
        /// </summary>
        /// <param name="buff"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public char[] InitMsg(char[] buff, char[] data)
        {
            char[] start = new char[] { '{' };
            char[] end = new char[] { '}' };
            char[] newrow = new char[] { '\r' };

            //Copy ký tự '{' vào đầu buff
            start.CopyTo(buff, 0);
            //Copy dữ liệu vào đầu buff
            data.CopyTo(buff, 1);
            //Copy ký tự kết thúc data '}' vào cuối buff
            end.CopyTo(buff, buff.Length - 2);
            //Copy ký tự new row '\r' vào cuối buff
            newrow.CopyTo(buff, buff.Length - 1);
            return buff;
        }

        /// <summary>
        /// Gửi thông tin gps theo string
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public char[] SendGPSData(string msg)
        {
            return SendGPSData(msg.ToCharArray());
        }

        /// <summary>
        /// Gửi thông tin gps theo mảng char[]
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public char[] SendGPSData(char[] data)
        {
            char[] buff = new char[GeneralClass.FULL_DATA_LEN];

            buff = InitMsg(buff, data);

            //Convert sang bytes
            byte[] buffBytes = Encoding.ASCII.GetBytes(buff);
            try
            {
                //send data
                WriteBytes(buffBytes, 0, buffBytes.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Xảy ra lỗi khi kết nối:\n" + ex.Message, "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return buff;
        }

        
        private byte[] tempBuff = new byte[4096];
        private int lenBuff = 0;

        //Event dùng nhận dữ liệu mới nhất
        public SerialDataReceivedEventHandler comPort_DataReceivedEvent;
        //Event dùng cho hiển thị kết quả ra datagridview
        public SerialDataReceivedEventHandler comPort_DataReceivedGridViewEvent;
        //Event dùng cho hiển thị kết quả log
        public SerialDataReceivedEventHandler comPort_DataReceivedEventLog;
        public void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (comPort.BytesToRead >= 39)
            {
                //StreamWriter sw = File.AppendText(GeneralClass.LogsFile);
                ListMessages = new List<string>();
                gpsPointList = new List<BaseGPSPoint>();
                //Vị trí index trong mảng tempBuff
                int index = 0;
                try
                {

                    int length = comPort.BytesToRead;
                    //Đọc dữ liệu từ cổng COM vào buffer tempBuff tại vị trí lenBuff
                    comPort.Read(tempBuff, lenBuff, length);
                    lenBuff += length; //số byte đọc từ cổng COM chưa xử lý xong

                    // Add some text to the file.
                    //sw.WriteLine();
                    string temp = Encoding.ASCII.GetString(tempBuff, 0, lenBuff);
                    string log = string.Format("[{0}] [ComBuffer] [Len:{1}] [{2}]", DateTime.Now, lenBuff, temp);
                    //sw.WriteLine(log);
                    ListMessages.Add(log);
                    if (comPort_DataReceivedEventLog != null)
                        comPort_DataReceivedEventLog(sender, e);

                    //Trong khi lenBuff - index >= LEN_DATA byte thì tiếp tục đọc
                    while (lenBuff - index >= GeneralClass.FULL_DATA_LEN)
                    {
                        //Nếu vị trí i chứa ký tự đầu chuỗi dữ liệu từ GPS '{'
                        if (tempBuff[index] == '{')
                        {
                            //Đọc hết 39 byte bằng phương pháp GetString
                            string tmpMsg = Encoding.ASCII.GetString(tempBuff, index, GeneralClass.FULL_DATA_LEN);
                            // Create an instance of StreamWriter to write text to a file.
                            // The using statement also closes the StreamWriter.

                            // Add some text to the file.
                            log = string.Format("[{0}] [Data] [{1}]", DateTime.Now, tmpMsg);
                            //sw.WriteLine(log);
                            ListMessages.Add(log);
                            if (comPort_DataReceivedEventLog != null)
                                comPort_DataReceivedEventLog(sender, e);

                            byte[] buff = Encoding.ASCII.GetBytes(tmpMsg);
                            //Kiểm tra xem cuối chuỗi có đúng là ký tự kết thúc chuỗi không '\r'
                            if (buff[buff.Length - 1] == '\r')
                            {
                                if (tmpMsg.StartsWith("{")) // && _isText)
                                {
                                    //nhận và hiển thị nội dung chat
                                    int startIndex = tmpMsg.IndexOf("{");
                                    int endIndex = tmpMsg.IndexOf("}");
                                    string msg = tmpMsg.Substring(startIndex + 1, endIndex - startIndex - 1);

                                    ListMessages.Add(msg); //thêm vào danh sách tin
                                    if (comPort_DataReceivedEventLog != null)
                                        comPort_DataReceivedEventLog(sender, e);

                                }
                            }

                            //Tăng index sau khi đọc xong chuỗi dữ liệu GPS
                            index += GeneralClass.FULL_DATA_LEN;
                        }
                        else
                        {
                            index++;
                        }
                    }



                    //Xử lý dữ liệu còn lại nếu chưa đủ byte cần nhận
                    //Bằng cách chuyển số byte còn lại về đầu mảng tempBuff
                    lenBuff -= index;
                    if (lenBuff > 0)
                    {
                        //Đọc hết dữ liệu còn lại của tempBuff thành chuỗi string
                        string tempDataString = Encoding.ASCII.GetString(tempBuff, index, lenBuff);
                        //Khởi tạo lại mảng tempBuff
                        tempBuff = new byte[4096];
                        //convert dữ liệu string sang lại mảng byte
                        byte[] tempDataByte = Encoding.ASCII.GetBytes(tempDataString);
                        //Copy vào đầu mảng byte tempBuff
                        tempDataByte.CopyTo(tempBuff, 0);
                    }

                    //Sau khi xử lý xong buffer thì hiển thị lên bản đồ
                    //Bằng cách gọi các event đã khai báo ở form khác
                    if (comPort_DataReceivedEvent != null)
                        comPort_DataReceivedEvent(sender, e);
                    if (comPort_DataReceivedGridViewEvent != null)
                        comPort_DataReceivedGridViewEvent(sender, e);
                }
                catch (Exception ex)
                {
                    string msg = ex.Message;
                    // Add some text to the file.
                    //sw.WriteLine(string.Format("[{0}] [Error] [{1}]", DateTime.Now, msg));
                }
                //sw.Close();
            }
        }


        public void comPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            //nếu truyền lỗi
            MessageBox.Show("Có lỗi truyền tin");
            comPort.Close();
            CountReceived = 0;
            buffer = null;
            lblSendingStatus.Text = "Đã có lỗi truyền tin!";
        }

        /// <summary>
        /// HT Code
        /// </summary>
        public char[] WriteAck()
        {
            char[] buff = new char[11]; //kích thước mặc định là 39 bytes
            //HT Code: thông báo đã nhận thành công
            char[] data = ACK_MSG.ToCharArray();
            buff = InitMsg(buff, ACK_MSG.ToCharArray());

            //Convert sang bytes
            byte[] buffBytes = Encoding.ASCII.GetBytes(buff);
            try
            {
                //send data
                WriteBytes(buffBytes, 0, buffBytes.Length);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Xảy ra lỗi khi kết nối:\n" + ex.Message, "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return buff;
        }

        public byte[] GetFullBufferMessage(string str)
        {
            byte[] arr = new byte[4096];
            byte[] strByteArr = new byte[str.Length];
            strByteArr = Encoding.ASCII.GetBytes(str);
            for (int i = 0; i < str.Length; i++)
            {
                arr[i] = strByteArr[i];
            }
            return arr;
        }

        public void WriteACK(string msg)
        {
            if (comPort.IsOpen)
            {
                comPort.Write(GetFullBufferMessage(msg), 0, 4096);
            }
            else
            {
                MessageBox.Show("Kết nối chưa được mở!", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        public void WriteBytes(byte[] buff, int offset, int length)
        {
            if (comPort.IsOpen)
            {
                try
                {
                    comPort.Write(buff, offset, length);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("WriteBytes" + ex.Message);
                    //throw;
                }
            }
            else
            {
                MessageBox.Show("Kết nối chưa được mở!", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        #endregion


        

        #region Comport Methods
        public bool IsOpen()
        {
            return comPort.IsOpen;
        }

        public void comPortOpen()
        {
            try
            {
                if (!comPort.IsOpen)
                {
                    comPort.PortName = _portName;
                    comPort.BaudRate = int.Parse(_baudRate);
                    comPort.Parity = (Parity)Enum.Parse(typeof(Parity), _parity);
                    comPort.DataBits = int.Parse(_dataBits);
                    comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), _stopBits);
                    comPort.Open();
                }
                else
                {
                    if (MessageBox.Show("Port đã sẵn sàng mở!\nBạn cần đóng nó trước khi mở trở lại!\nBạn có muốn thực hiện đóng kết nối hiện tại và mở lại kết nối này hay không?", "Thông báo", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                    {
                        //Ngắt và mở lại kết nối
                        comPort.Close();
                        comPortOpen();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Lỗi trong khi mở kết nối!");
                //if (MessageBox.Show("Lỗi trong khi mở kết nối!\n" + ex.Message + "\nBạn có muốn mở cửa sổ cấu hình kết nối?", "Thông báo", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                //{
                //    frmCOMSetting f = new frmCOMSetting();
                //    f.ShowDialog();
                //}
            }
        }

        public void comPortClose()
        {
            try
            {
                //Close the Port
                comPort.Close();
                buffer = null;
                count = 0;
                CountReceived = 0;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public List<string> getListPortName()
        {
            //lấy danh sách cổng COM có trên máy
            List<string> portNames = new List<string>();
            foreach (string c in SerialPort.GetPortNames())
            {
                portNames.Add(c);
            }
            return portNames;
        }

        public List<string> getListStopBit()
        {
            //lấy danh sách Stopbits
            List<string> stopBits = new List<string>();
            foreach (string c in Enum.GetNames(typeof(StopBits)))
            {
                if (c != "None")
                    stopBits.Add(c);
            }
            return stopBits;
        }

        public List<string> getListParity()
        {
            //lấy danh sách Parity
            List<string> parity = new List<string>();
            foreach (string c in Enum.GetNames(typeof(Parity)))
            {
                parity.Add(c);
            }
            return parity;
        }

        public List<string> getListBaudrate()
        {
            string[] lstBaudRate = { "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200" };
            List<string> baudRates = new List<string>();
            foreach (string c in lstBaudRate)
            {
                baudRates.Add(c);
            }
            return baudRates;
        }

        public List<string> getListDataBits()
        {
            string[] lstDataBits = { "7", "8", "9" };
            List<string> dataBits = new List<string>();
            foreach (string c in lstDataBits)
            {
                dataBits.Add(c);
            }
            return dataBits;
        }

        public enum DefaultSettings
        {
            COM1,
            BaudRate = 9600,
            None,
            DataBit = 8
        }

        public void getDefaultSettings(ref string _BaudRate, ref string _StopBit, ref string _DataBit, ref string _Parity)
        {
            _baudRate = "9600";
            _StopBit = "None";
            _DataBit = "8";
            _parity = "None";
        }
        #endregion

        //#region Display Methods

        //public string ProcessMessageReceived(string msg)
        //{
        //    return "";
        //}

        //#endregion
    }
}

